#include "../include/Channel.h"
#include "../include/EventLoop.h"

Channel::Channel(EventLoop *loop, int fd)
    : _fd(fd),
      _loop(loop),
      _events(0),
      _revents(0) {}

int Channel::getFd() { return _fd; }
uint32_t Channel::getEvents() { return _events; }
void Channel::setRevents(uint32_t revents) { _revents = revents; }
bool Channel::ReadAble() { return _events & EPOLLIN; }
bool Channel::WriteAble() { return _events & EPOLLOUT; }
void Channel::EnableRead()
{
    _events |= EPOLLIN;
    Update();
}

void Channel::EnableWrite()
{
    _events |= EPOLLOUT;
    Update();
}

void Channel::DisableRead()
{
    _events &= (~EPOLLIN);
    Update();
}

void Channel::DisableWrite()
{
    _events &= (~EPOLLOUT);
    Update();
}

void Channel::DisableAll()
{
    _events = 0;
    Update();
}

void Channel::Remove()
{
    // _poller->RemoveEvents(this);
    _loop->RemoveEvent(this);
}

void Channel::Update()
{
    // _poller->UpdateEvents(this);
    _loop->UpdateEvent(this);
}
void Channel::SetReadCallBack(const EventCallBack &rcb) { _read_callback = rcb; }
void Channel::SetWriteCallBack(const EventCallBack &wcb) { _write_callback = wcb; }
void Channel::SetErrorCallBack(const EventCallBack &ecb) { _error_callback = ecb; }
void Channel::SetCloseCallBack(const EventCallBack &ccb) { _close_callback = ccb; }
void Channel::SetRandomCallBack(const EventCallBack &rdmcb) { _random_callback = rdmcb; }

void Channel::HandleEvent()
{
    const uint32_t READ_MASK = EPOLLIN | EPOLLRDHUP | EPOLLPRI;

    const bool hasRead = _revents & READ_MASK;
    const bool hasWrite = _revents & EPOLLOUT;
    const bool hasErr = _revents & EPOLLERR;
    const bool hasHup = _revents & EPOLLHUP;

    if (hasRead)
    {
        safeCall(_random_callback);
        safeCall(_read_callback);
    }

    if (hasWrite)
    {
        safeCall(_random_callback);
        safeCall(_write_callback);
    }

    if (hasErr)
    {
        safeCall(_random_callback);
        safeCall(_error_callback);
    }

    if (hasHup && !hasRead)
    {
        safeCall(_random_callback);
        safeCall(_close_callback);
    }
}

void Channel::safeCall(const std::function<void()> &cb)
{
    if (cb)
        cb();
}
